﻿Imports System.Text

Namespace MySQL
    ''' <summary>
    ''' MySQLテーブル生成
    ''' </summary>
    ''' <remarks>#97　MySQL対応</remarks>
    Public Class TableFactory
        Inherits TableFactoryBase

        Private Shared tables As New HashSet(Of String)

        ''' <summary>
        ''' 読み込み、生成処理の関数を示します。
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks>差し替え可能です。</remarks>
        Public Shared Property Creater As Action(Of Type, Action(Of ColumnDefinitionAttribute)) = AddressOf (New Kairyu.Extensions.DDL.MySQL.ColumnDefinitionAttributeFactory).Create

        Protected Overrides Sub CreateCore(cn As IDbConnection, ts As IEnumerable(Of Type))
            Dim fn As Func(Of String, InfoLevelEnum, IDbCommand) =
                Function(s, lv)
                    Dim cmd As IDbCommand = cn.CreateCommand
                    cmd.CommandText = s
                    Log.OnExecuteCommand.Invoke(Nothing, New CreateDbCommandEventArgs(cmd) With {.CommandInfoLevel = lv})
                    Return cmd
                End Function

            For Each item In ts
                Dim def As TableDefinition = TableDefinitionReader.Read(item, Creater)
                If def.ColumnDefinisions.Any = False Then Continue For

                'AutoKeyはサポートしていないので、無視
                If (From el In def.ColumnDefinisions Where TypeOf el.Column.Key Is AutoKeyAttribute).Any Then Continue For

                fn.Invoke(Me.CreateCommandText(def), InfoLevelEnum.Warn).ExecuteNonQuery()
            Next
        End Sub

        Private Function CreateCommandText(def As TableDefinition) As String
            Dim s As New StringBuilder

            'CREATE / DROP TABLE がものすごく遅いので別の方法で実装
            If tables.Contains(def.Table.TableFullName) = False Then
                s.AppendFormat("DROP TABLE IF EXISTS {0};", def.Table.TableFullName)
                s.AppendFormat("CREATE TABLE {0} ({1});", def.Table.TableFullName, CreateColumnDefinitionText(def))
                tables.Add(def.Table.TableFullName)
            Else
                s.AppendFormat("DELETE FROM {0};", def.Table.TableFullName)
            End If

            Return s.ToString
        End Function

        Private Function CreateColumnDefinitionText(def As TableDefinition)
            Dim s As String = String.Empty
            Dim add As Action(Of String) =
                Sub(text)
                    If String.IsNullOrEmpty(text) Then Return
                    If String.IsNullOrEmpty(s) = False Then s &= ", "
                    s &= text
                End Sub

            '列
            For Each item In def.ColumnDefinisions
                add.Invoke(item.ColumnFullText)
            Next

            '制約
            add.Invoke(Me.CreatePrimaryKeyDefinitionText(def))
            add.Invoke(Me.CreateUniqueDefinitionText(def))

            Return s
        End Function

        Private Function CreatePrimaryKeyDefinitionText(def As TableDefinition) As String
            Dim s As String = String.Empty
            Dim add As Action(Of String) =
                Sub(text)
                    If String.IsNullOrEmpty(s) = False Then s &= ", "
                    s &= text
                End Sub

            For Each item In (From el In def.ColumnDefinisions Where el.Column.IsPrimaryKey Order By el.Index)
                add.Invoke(item.Column.ColumnName)
            Next

            Return If(String.IsNullOrEmpty(s), s, String.Format("CONSTRAINT PK_{0} PRIMARY KEY({1})", def.Table.TableName, s))
        End Function

        Private Function CreateUniqueDefinitionText(def As TableDefinition) As String
            Dim s As String = String.Empty
            Dim add As Action(Of String) =
                Sub(text)
                    If String.IsNullOrEmpty(s) = False Then s &= ", "
                    s &= text
                End Sub

            For Each item In (From el In def.ColumnDefinisions Where el.Column.IsAlternativeLoadKey Order By el.Index)
                add.Invoke(item.Column.ColumnName)
            Next

            Return If(String.IsNullOrEmpty(s), s, String.Format("CONSTRAINT UQ_{0} UNIQUE ({1})", def.Table.TableName, s))
        End Function
    End Class

End Namespace
